#include "stdafx.h"
#include <cassert>
#include <vector>
#include <rt/Exceptions/COMException.h>
#include <rt/Exceptions/NotImplementedException.h>

namespace rt
{

class DeviceEnumerator : public IDeviceEnumerator
{
public:
	DeviceEnumerator(IDirect3D9 *d3d);
	virtual ~DeviceEnumerator() { }

	void Enumerate(IDeviceEnumerationFilter *filter);
	UINT GetNumCombinations() const;
	DeviceCombination const &GetCombination(UINT i) const;

private:
	IDirect3D9Ptr m_d3d;
};

DeviceEnumerator::DeviceEnumerator(IDirect3D9 *d3d)
	: m_d3d(d3d)
{
}

#define NUM_OF(ary_) (sizeof(ary_)/sizeof(ary_[0]))

void DeviceEnumerator::Enumerate(IDeviceEnumerationFilter *filter)
{
	assert(filter && "No callback specified");
	struct AdapterFormatModeCombination
	{
		AdapterFormatModeCombination(UINT adapter, D3DFORMAT format, D3DDISPLAYMODE const &mode)
			: m_adapter(adapter),
			m_format(format),
			m_mode(mode)
		{
		}
		UINT m_adapter;
		D3DFORMAT m_format;
		D3DDISPLAYMODE m_mode;
	};
	std::vector<AdapterFormatModeCombination> combinations;
	for (UINT adapter = 0; adapter < m_d3d->GetAdapterCount(); ++adapter)
	{
		D3DFORMAT const formats[] = {
			D3DFMT_A1R5G5B5, D3DFMT_X1R5G5B5, D3DFMT_R5G6B5,
			D3DFMT_A8R8G8B8, D3DFMT_X8R8G8B8,
			D3DFMT_A2R10G10B10
		};
		for (int f = 0; f < NUM_OF(formats); f++)
		{
			D3DFORMAT format = formats[f];
			for (UINT m = 0; m < m_d3d->GetAdapterModeCount(adapter, format); m++)
			{
				D3DDISPLAYMODE mode;
				THR(m_d3d->EnumAdapterModes(adapter, format, m, &mode));
				if (filter->IsDisplayModeAcceptable(mode))
				{
					combinations.push_back(AdapterFormatModeCombination(adapter, format, mode));
				}
			}
		}
	}
	D3DCAPS9 caps;
	THR(m_d3d->GetDeviceCaps(0, D3DDEVTYPE_HAL, &caps));
	D3DFORMAT adapterFormat = D3DFMT_X8R8G8B8;
	D3DFORMAT backBufferFormat = D3DFMT_X8R8G8B8;
	bool windowed = false;
	filter->IsDeviceAcceptable(caps, adapterFormat, backBufferFormat, windowed);
}

UINT DeviceEnumerator::GetNumCombinations() const
{
	throw rt::NotImplementedException();
}

rt::DeviceCombination const &DeviceEnumerator::GetCombination(UINT i) const
{
	throw rt::NotImplementedException();
}

}

extern "C" rt::IDeviceEnumerator *rtCreateDeviceEnumerator(IDirect3D9 *d3d)
{
	assert(d3d && "No IDirect3D9 interface specified");
	return new rt::DeviceEnumerator(d3d);
}
